package apis

import (
	"net/http"

	"gitee.com/sansaniot/ssiot-core/httpmvc/api"
	jwt "gitee.com/sansaniot/ssiot-core/httpmvc/jwtauth"
	"gitee.com/sansaniot/ssiot-core/ws"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"github.com/mitchellh/mapstructure"

	"ssdevice/common/constant"
	"ssdevice/internal/device/models/query"
)

type WsApi struct {
	api.Api
}

// 查询当前客户端
func (e WsApi) FindClients(c *gin.Context) {
	// 请求参数
	req := query.WsQuery{}
	// 上下文
	err := e.MakeContext(c).Bind(&req).MakeOrm().Errors
	if err != nil {
		e.Logger.Error(err)
		e.Fail(0, err.Error())
		return
	}
	req.LoadUser(c)
	if req.UserId != "1" {
		e.Ok(make([]map[string]interface{}, 0))
		return
	}
	// 返回
	e.Ok(ws.GetStatusInfo())
}

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

// websocket服务
func (e WsApi) ConnectAndListen(c *gin.Context) {
	// 请求参数
	req := query.WsQuery{}
	// 上下文
	err := e.MakeContext(c).Bind(&req).MakeOrm().Errors
	if err != nil {
		e.Logger.Error(err)
		e.Fail(0, err.Error())
		return
	}
	// 校验token
	if authMiddleware, ok := c.Get("authMiddleware"); !ok || authMiddleware == nil {
		return
	} else {
		c.Request.Header.Set("Authentication", req.Token)
		f := (authMiddleware.(*jwt.GinJWTMiddleware)).MiddlewareFuncWithOutValidate()
		f(c)
	}
	if _, ok := c.Get(constant.JwtKeyUserName); !ok {
		return
	}
	// 用户信息
	req.LoadUser(c)
	upgrader.CheckOrigin = func(r *http.Request) bool {
		return true
	}
	upgrader.Subprotocols = []string{c.GetHeader("Sec-WebSocket-Protocol")}
	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		e.Logger.Error(err)
		e.Fail(0, err.Error())
		return
	}
	// 客户端
	client := &ws.Client{
		ClientBroadFilter: clientMsgFilter,
		ClientMsgRecv:     clientMsgIn,
	}
	// 是否首次加载(需要指定参数,避免查询全部)
	if req.NeedFirst && (len(req.Sn) > 0 || len(req.ProductModel) > 0) {
		client.ClientConnCall = connGetData
	}
	// 客户端请求参数
	_ = mapstructure.Decode(req, &client.Param)
	// 客户端权限
	_ = mapstructure.Decode(req.UserInfo, &client.Auth)
	client.SetConn(conn)
	// 加入连接池
	client.Client2Hub()
}
